var newLine = "\n";
var spaceRegExp = /\s+/;

function Sos(form){

	var codes = document.getElementsByName("#code");
	for(var i=0; i<codes.length; i++){
		codes[i].innerHTML = GetCode(codes[i].id);
	}
}

function GetCode(pattern){
	var code = Query(pattern); 
	code = AddDefine(code);
	code = ClearComments(code);
	code = PreProcess(code);
	code = ClearEmptyLines(code);
	code = colorCode(code);
	code = AddIncludedFilesLink(code);
	return code;
}

function AddDefine(code){

	var newDefine = "";
	
	var defines = document.getElementsByName("#define");
	for(var i=0; i<defines.length; i++){
		if(defines[i].type == "checkbox" && !defines[i].checked){
			continue;
		}
		newDefine += "#define " + defines[i].id + " " + defines[i].value + newLine;
	}
	return newDefine + code;
}

/**
	#define and #if must be the begin of a line
	only macro that begin with PreProcessDefineHead would be repalced
	macro in muti-line ( end with "\")  is not supported
	nest #if is not supported
	#if a == b
*/
function PreProcess(code){
	var defineToken = "#define";
	var ifToken = "#if";
	var elifToken = "#elif";
	var elseToken = "#else";
	var endifToken = "#endif";
	
	var forToken = "#for";
	var endforToken = "#endfor";

	var PreProcessDefineHead = "SOS_";


	var fetched = "";
	var remain = code;
	
	while(true){
		var lines = remain.explode( newLine, 2);
		if(lines.length < 2){
			break;
		}
		var line = lines[0];
		var remain = lines[1];
		tokens = line.split(spaceRegExp);

		if( tokens[0] == defineToken ){
			var tokens = line.explode(spaceRegExp, 3);
			if( tokens[1].startsWith( PreProcessDefineHead)){
				var re = new RegExp( "\\b" + tokens[1] + "\\b" ,"g");
				remain = remain.replace( re, tokens[2]);
			}
			else{
				fetched = fetched + newLine + line;
			}
		}
		else if( tokens[0] == forToken ){
			var count = tokens[1];
			var pattern = remain.beforeString(endforToken).replace(/\#/g, "");
			var forContent = "";
			for(var i=0; i<count; i++){
				forContent += pattern.replace(/\$/g, i, "g");
			}
			remain = forContent + remain.afterString(endforToken);
		}
		else if( tokens[0] == ifToken ){
			var elifStart = remain.indexOf(elifToken);
			var elseStart = remain.indexOf(elseToken);
			var endifStart = remain.indexOf(endifToken);
 

			if( elifStart > endifStart ){
				elifStart = -1;
			}
			if( elseStart > endifStart ){
				elseStart = -1;
			}
			
			if( (tokens[1] == "undefined") 
				|| (tokens[2] == "==") && (tokens[1] == tokens[3]) 
				|| (tokens[2] != "==") && !tokens[1].startsWith( PreProcessDefineHead ))
			{
				// Hi();
				var ifEnd;
				if(elifStart>0){
					ifEnd = elifStart;
				}
				else if(elseStart > 0){
					ifEnd = elseStart;
				}
				else{
					ifEnd = endifStart;
				}
				remain = remain.substring(0, ifEnd) 
					+ remain.substring(endifStart + endifToken.length);
			}
			else{
				if(elifStart>0){
					remain = ifToken + remain.substring( elifStart + elifToken.length );
				}
				else if(elseStart > 0){
					remain = remain.substring( elseStart + elseToken.length, endifStart)
						+ remain.substring(endifStart + endifToken.length);
				}
				else{
					remain = remain.substring(endifStart + endifToken.length);
				}
			}
		}
		else{
			fetched += line + newLine;
		}
	}
	code = fetched + newLine + remain;
	
	return code;
}

function ClearComments(code){
	
	var inlineComment =  new RegExp( "([^/])//[^/].*" ,"g");
	code = code.replace( inlineComment, '$1');

	var blockComment =  new RegExp( "\\/\\*[^*][\\s\\S]+?\\*\\/" ,"g");
	code = code.replace( blockComment, "");

	return code;
}

function ClearEmptyLines(code){

	var re = new RegExp( "(\\s*" +  newLine + "){2,}","g");
	code = code.replace(re, newLine + newLine);
	return code;
}

function AddIncludedFilesLink(code){

	var re = new RegExp( "#include\\s+\\\"([^\\\"]+)\"","g");
	code = code.replace(re, "#include \"<a href='" + '$1' + "' target='_blank' >" + '$1' + "</a>\"" );
	return code;
}
